package com.systar.activity.monitor;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.systar.activity.events.FileDetectionEvent;
import com.systar.activity.events.ParsingActivityEvent;
import com.systar.activity.events.StatusActivityEvent;
import com.systar.activity.process.ActivitySourceObserver;
import com.systar.activity.state.FileActivity;

public class ActivitySource 
{
	private final ActivityManager manager;
	private final String name;
	private final String location;
	private final ScheduledExecutorService scheduler;
	private final ActivitySourceObserver observer;
	private ActivityRecorder recorder;

	private final Map<File, FileActivity> filesToActivity;
	private final Map<FileActivity, FileActivity> runningActivities;
	private final EventBus eventBus;

	public ActivitySource(ActivityManager manager, String name, String location)
	{
		this.manager = manager;
		this.name = checkNotNull(name);
		this.location = checkNotNull(location);
		
		eventBus = new EventBus(name);
		eventBus.register(this);
		
		scheduler = Executors.newSingleThreadScheduledExecutor();
		observer = new ActivitySourceObserver(eventBus);
		filesToActivity = new HashMap<File, FileActivity>();
		runningActivities = new IdentityHashMap<FileActivity, FileActivity>();
		
		recorder = new ActivityRecorder("Source "+name+" (events per sec)");
	}
	
	@VisibleForTesting
	public EventBus getEventBus()
	{
		recorder.start();
		return eventBus;
	}

	public String getName()
	{
		return name;
	}

	public String getLocation()
	{
		return location;
	}

	public void activateObserver()
	{
		try
		{
			System.out.println("activate observer for Source "+name);
			observer.connect(location, null);
		}
		catch (IOException e)
		{
			/*MessageBox messageBox = new MessageBox(null, SWT.ICON_ERROR);
			messageBox.setMessage("Message");
			messageBox.open();*/
			System.err.println(e.getMessage());
			// ESCA-JAVA0265: for debugging
			e.printStackTrace();
		}
		scheduler.scheduleWithFixedDelay(observer, 0, 1, TimeUnit.SECONDS);
	}

	public void deactivateObserver()
	{
		scheduler.shutdown();
	}

	@Subscribe
	public void handleStartFileActivity(FileDetectionEvent fileEvent)
	{
		File file = fileEvent.getFile();
		FileActivity activity;
		if (filesToActivity.containsKey(file))
		{
			activity = filesToActivity.get(fileEvent.getFile());
		}
		else
		{
			activity = new FileActivity(this, file);
			filesToActivity.put(file, activity);
		}
		if (!runningActivities.containsKey(activity))
		{
			if (runningActivities.isEmpty())
			{
				// post event if start to parse
				manager.handleDisplayEvent(new StatusActivityEvent(this, true));
				recorder.start();
			}
			runningActivities.put(activity, activity);
			manager.parseFile(activity, eventBus);
		}
	}

	@Subscribe
	public void handleFinishFileActivity(FileActivity activity)
	{
		runningActivities.remove(activity);
		if (runningActivities.isEmpty())
		{
			// post event if no more parsing 
			manager.handleDisplayEvent(new StatusActivityEvent(this, false));
			recorder.end();
			System.out.println(recorder.formatResult());
		}
	}

	@Subscribe
	public void handleParsingFileActivity(ParsingActivityEvent parsingEvent)
	{
		parsingEvent.setSource(this);
		manager.handleDisplayEvent(parsingEvent);
		recorder.increment();
	}

	/**
	 * @return the serialization string for server
	 */
	public String marshal()
	{
		return "source="+getName();
	}

}
